package cn.oi.klittle.era.socket

import android.content.Context
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import cn.oi.klittle.era.base.KBaseApplication
import cn.oi.klittle.era.exception.KCatchException
import cn.oi.klittle.era.utils.KLoggerUtils
import java.io.*
import java.net.*
import java.net.NetworkInterface.getNetworkInterfaces
import java.util.*
import java.util.regex.Pattern


/**
 * ip地址和端口号
 * 理论上IP的范围是0.0.0.0~255.255.255.255
 * 端口号为1~65535
 * 服务器端（本地服务器，必须确保客户端和服务器在同一局域网中才能通信）
 * 局域网，即同一个网段下，即IP地址的前三段必须相同。如：192.168.1.110，即192.168.1 前三段相同，就属于同一个网段。
 */
open class KIpPort {
    //内网IP4地址
    var hostIp4: String? = null
        get() {
            return getHostIp4()//防止更改，每次都实时获取。
        }

    //外网IP4地址,要放到后台线程里处理
    var netIp4: String? = null
        get() {
            return getNetIp4()
        }

    //当前要使用的ip4地址和端口号
    var Ip4: String? = hostIp4 //这里Ip4和hostIp4只是赋值。不是同一个对象。
    var Port = defaultPort
        set(value) {
            field = Companion.port(value)
        }

    companion object {
        var defaultPort = 31053//默认端口号

        //获取或设置端口号
        fun port(port: Int = defaultPort): Int {
            //端口号规定为16位，即允许一个IP主机有2的16次方65535个不同的端口
            //0~1023：分配给系统的端口号,如果设置端口为0，则系统会自动为其分配一个端口；
            //1024~49151：登记端口号，主要是让第三方应用使用
            //49152~65535：短暂端口号，是留给客户进程选择暂时使用，一个进程使用完就可以供其他进程使用。
            if (port < 1024 || port > 65535) {
                return defaultPort//默认端口号
            } else {
                return port
            }
        }

        //获取ip地址+端口号port 形式为 192.168.0.1:8889
        fun getIpPort(ip: String?, port: Int?): String? {
            return ip + ":" + port
        }

        //获取内网IP4地址【绝对可行】
        fun getHostIp4(): String? {
            var hostIp: String? = null
            try {
                val nis = NetworkInterface.getNetworkInterfaces()
                var ia: InetAddress? = null
                while (nis.hasMoreElements()) {
                    val ni = nis.nextElement() as NetworkInterface
                    val ias = ni.inetAddresses
                    while (ias.hasMoreElements()) {
                        ia = ias.nextElement()
                        if (ia is Inet6Address) {
                            continue// skip ipv6,跳过IP6地址
                        }
                        val ip = ia!!.hostAddress
                        if ("127.0.0.1" != ip) {
                            hostIp = ia.hostAddress
                            break
                        }
                    }
                }
            } catch (e: SocketException) {
                e.printStackTrace()
                KLoggerUtils.e("test", "IP获取异常:\t" + e.message)
            }
            return hostIp
        }

        //获取外网的IP(要访问Url，要放到后台线程里处理)，也是IP4地址
        fun getNetIp4(): String? {
            var infoUrl: URL? = null
            var inStream: InputStream? = null
            var ipLine: String? = null
            var httpConnection: HttpURLConnection? = null
            try {
                //infoUrl = new URL("http://ip168.com/");
                infoUrl = URL("http://pv.sohu.com/cityjson?ie=utf-8")
                val connection = infoUrl.openConnection()
                httpConnection = connection as HttpURLConnection
                val responseCode = httpConnection.responseCode
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    inStream = httpConnection.inputStream
                    val reader = BufferedReader(
                            InputStreamReader(inStream!!, "utf-8"))
                    val strber = StringBuilder()
                    var line: String? = reader.readLine()
                    while (line != null) {
                        strber.append(line!! + "\n")
                        line = reader.readLine()
                    }
                    val pattern = Pattern
                            .compile("((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d))))")
                    val matcher = pattern.matcher(strber.toString())
                    if (matcher.find()) {
                        ipLine = matcher.group()
                    }
                }
            } catch (e: MalformedURLException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                try {
                    inStream!!.close()
                    httpConnection!!.disconnect()
                } catch (e: IOException) {
                    e.printStackTrace()
                } catch (ex: Exception) {
                    ex.printStackTrace()
                }
            }
            return ipLine
        }

        //获取内网IP6地址
        fun getHostIp6(): String? {
            try {
                val en = NetworkInterface
                        .getNetworkInterfaces()
                while (en.hasMoreElements()) {
                    val intf = en.nextElement()
                    val enumIpAddr = intf
                            .inetAddresses
                    while (enumIpAddr.hasMoreElements()) {
                        val inetAddress = enumIpAddr.nextElement()
                        if (!inetAddress.isLoopbackAddress) {
                            return inetAddress.hostAddress.toString()
                        }
                    }
                }
            } catch (ex: SocketException) {
            }

            return null
        }

        private var mMac: String = "02:00:00:00:00:00"//fixme  02:00:00:00:00:00是常量；如果返回这个肯定就是错误的，不是真实的mac地址
        private var mac: String? = null

        //fixme 获取mac地址，亲测不需要任何权限。
        //通过wifi（与wifi是否开启没有关系，亲测能够获取） 获取mac地址[物理地址，不会变。理论上是不变，因为是出厂时被厂家烧在网卡上的。但不能保证绝对。]
        fun getMacAddress(): String {
            try {
                if (Build.VERSION.SDK_INT < 23) {
                    if (mac == null) {
                        var wifi = KBaseApplication.getInstance().baseContext.getSystemService(KBaseApplication.WIFI_SERVICE) as WifiManager
                        var info = wifi.getConnectionInfo()//fixme 亲测，不需要任何权限。
                        mac = info.getMacAddress()//6.0及以上，无法获取正在的mac地址。返回的是固定的：02:00:00:00:00:00
                    }
                    mac?.trim()?.let {
                        if (it.equals(mMac)) {
                            mac = getHightMac()
                        }
                    }
                } else {
                    if (mac == null) {
                        mac = getHightMac()
                    }
                    mac?.trim()?.let {
                        if (it.length <= 0) {
                            mac = getHightMac()
                        }
                    }
                }
                mac?.let {
                    return it
                }
            } catch (e: Exception) {
                KLoggerUtils.e("getMacAddress()mac地址获取异常：\t" + KCatchException.getExceptionMsg(e), isLogEnable = true)
            }
            return mMac
        }

        //fixme 6.0(api23)及以上获取mac地址。亲测可行(不需要任何权限)。能够获取设备真正的mac地址。获取出来的MAC地址都是大写的；如：98:6C:F5:55:B6:82
        private fun getHightMac(): String? {
            var mac: String? = ""
            try {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                    val wifiManage: WifiManager =
                            KBaseApplication.getInstance().baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
                    val wifiInfo: WifiInfo? = wifiManage.connectionInfo
                    mac = wifiInfo?.macAddress
                } else {
                    var address = ""
                    val interfaces: Enumeration<NetworkInterface> =
                            NetworkInterface.getNetworkInterfaces()
                    while (interfaces.hasMoreElements()) {
                        val netWork: NetworkInterface = interfaces.nextElement()
                        val by = netWork.hardwareAddress
                        if (by == null || by.isEmpty()) {
                            continue
                        }
                        val builder = StringBuilder()
                        for (b in by) {
                            builder.append(String.format("%02X:", b))
                        }
                        if (builder.isNotEmpty()) {
                            builder.deleteCharAt(builder.length - 1)
                        }
                        val macAddress = builder.toString()
                        // 从路由器上在线设备的MAC地址列表，可以印证设备Wifi的 name 是 wlan0
                        if (netWork.name == "wlan0") {
                            address = macAddress
                        }
                    }
                    mac = address
                }
            } catch (e: Exception) {
                e.printStackTrace()
                mac = ""
                KLoggerUtils.e("getHightMac()mac地址获取异常：\t" + KCatchException.getExceptionMsg(e), isLogEnable = true)
            }
            return mac
        }

    }

}